#! /usr/bin/env Python3
#coding=utf-8

"""
自己编写的人工智能程序使用的数据预处理相关的函数
作者: KydGroups
版本: 1.0.0
完成日期: 2024-12-03
修改记录:
"""
import math

def SplitStrToFloat(strLine:str="", nValid:int=4, charDelimiter:str=','):
    """
    :DESCRIPTION:
        将字符串分隔成浮点数数组
    :PARAMS:
        strLine: 字符串组成的数据
        nValid: 浮点数有效小数位数
        charDelimiter: 字符串中数字的分隔符
    :RETURNS:
        None:出错或没有分隔成数字 List:分隔成的数字
    """
    if not strLine: #如果没有传入要分隔的字符串
        return []
    if not (2 <= nValid <= 10): #浮点数有效小数位数范围为2-10
        nValid = 4
    strTemp = strLine.strip() #将传入的字符串有效字符去掉
    listSplit = strTemp.split(charDelimiter) #将字符串分隔
    if not listSplit: #如果没有分隔成功
        return []
    else:
        listReturn = []
        for item in listSplit: #对每一个分隔后的数字进行处理
            fValue = round( float(item.strip()), nValid) #转换成有效位数的浮点数
            listReturn.append(fValue) #将转换后的数字添加进返回列表中
        if len(listReturn) == 0: #如果没有返回的数据
            return []
        else:
            return listReturn


def JoinFloatToStr(listData:list=[], nValid:int=4, charDelimiter:str=','):
    """
    :DESCRIPTION:
        将列表中的浮点数连接成字符串格式
    :PARAMS:
        listData: 要连接成字符串的数据列表
        nValid: 浮点数有效小数位数
        charDelimiter: 字符串中数字的分隔符
    :RETURNS:
        None:出错或没有分隔成数字 List:分隔成的数字
    """
    if not listData: #如果没有传入列表数据
        return ""
    if not (2 <= nValid <= 10): #浮点数有效小数位数范围为2-10
        nValid = 4
    strReturn = "" #临时使用的字符串
    strFormat = ("%%.%df%c" % (nValid,charDelimiter)) #转换为格式化
    for item in listData: #循环处理每一个浮点数
        strReturn += (strFormat % item)
    return strReturn[:-1] #去掉最后一个分隔符


def WriteParaDataToFile(strPath:str="", listData:list=[], nPerLine:int=10,
                        nValid:int=4, charDelimiter:str=',', strEncoding:str='utf-8'):
    """
    :DESCRIPTION:
        将参数数据写入文件
    :PARAMS:
        strPath: 数据文件的路径
        listData: 要写入文件的浮点数据列表
        nPerLine: 文件每一个写几个数字
        nValid: 浮点数有效小数位数
        charDelimiter: 字符串中数字的分隔符
        strEncoding: 文件的数字编码
    :RETURNS:
        True:写入成功 False:写入失败
    """
    if not strPath:
        return False
    if not listData:
        return False
    if not (5 <= nPerLine <= 50): #每一行最多写入50个数字
        nPerLine=10
    with open(file=strPath, mode='w+', encoding=strEncoding) as outfile: #打开文件准备写入数据
        nMax = len(listData) #数据最大长度
        nBegin = 0 #开始的位置长度
        nEnd = nBegin + nPerLine #结束集团的长度
        while nEnd < nMax: #只要还有数据
            listWrite = listData[nBegin:nEnd] #生成要写入的数据列表
            strWrite = JoinFloatToStr(listWrite, nValid, charDelimiter) #将浮点数据转换成字符串
            if not strWrite:#如果没有转换成功
                pass
            else:
                strWrite +='\n' #添加换行
                outfile.write(strWrite)
            nBegin = nEnd #调整开始与结束位置
            nEnd += nPerLine
        else: #循环结束
            if nBegin < nMax: #如果还有数据没有写入
                listWrite = listData[nBegin:] #最后一段数据列表
                strWrite = JoinFloatToStr(listWrite, nValid, charDelimiter) #将浮点数据转换成字符串
                if not strWrite:#如果没有转换成功
                    pass
                else:
                    outfile.write(strWrite)
    return True


def ReadParaDataFile(strPath:str="", nValid:int=4, charDelimiter:str=',', strEncoding:str='utf-8'):
    """
    :DESCRIPTION:
        从数据文件中添加浮点参数数据,注意:生成的是一维数组
    :PARAMS:
        strPath: 数据文件的路径
        nValid: 浮点数有效小数位数
        charDelimiter: 字符串中数字的分隔符
        strEncoding: 文件的数字编码
    :RETURNS:
        list:写入成功 []:读取失败
    """
    if not strPath:
        return []
    listReturn = []
    with open(file=strPath, mode='r', encoding=strEncoding) as infile: #读取文件
        listLines = infile.readlines() #读取全部文件行
        for strLine in listLines: #处理每一行数据
            listSplit = SplitStrToFloat(strLine, nValid, charDelimiter) #分隔一行数据
            if not listSplit: #如果没有分隔成功
                pass
            else:
                for item in listSplit: #将每一个数字添加时返回列表
                    listReturn.append(item)
    return listReturn


def DataStandard(listData:list=[], nValid:int=4, bLog:bool=False):
    """
    :DESCRIPTION:
        数据标准化,即将数据转换为0~1之间的数据
    :PARAMS:
        listData: 要转换的数据列表
        nValid: 浮点数有效小数位数
        bLog: 如果数据都非常大是否使用log10()进行处理
    :RETURNS:
        list:写入成功 []:读取失败
    """
    if not listData:
        return []
    try:
        listCompute = []
        fMax = 0.0
        fMin = 100.0
        for item in listData:
            fCur = item
            if bLog: #如果标记了log,则进行log10计算
                fCur = math.log10(item)
            listCompute.append(fCur) #将当前值添加进计算列表
            if fCur >= fMax: #如果出现最大值
                fMax = fCur
            if fCur <= fMin: #如果出现了最小值
                fMin = fCur
        fSize = fMax - fMin #计算数据差值
        listReturn = [] #返回用列表
        for item in listCompute: #进行数据标准化处理
            fValue = round((item - fMin)/fSize, nValid) #计算标准化值,并保留设置的数据精度
            listReturn.append(fValue)
        return listReturn #返回标准化后的数组
    except:
        print("数据标准化处理出现了错误!")
        return []
